package com.tabjin.rfidsocket.authority.shiro;

import org.apache.shiro.cache.MemoryConstrainedCacheManager;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.LinkedHashMap;

/**
 * @author tabjin
 * create at 2020/12/17 14:45
 * @program rfid_socket
 * @description Shiro Core Configuration
 */
//@Configuration
public class ShiroConfiguration {

    @Bean("shiroFilter")
    public ShiroFilterFactoryBean shiroFilter(@Qualifier("securityManager") SecurityManager securityManager) {
        ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
        shiroFilterFactoryBean.setSecurityManager(securityManager);

        shiroFilterFactoryBean.setLoginUrl("/user/login");// 登录的 url
        shiroFilterFactoryBean.setSuccessUrl("/user/index");// 登录成功之后跳转 url
        shiroFilterFactoryBean.setUnauthorizedUrl("/users/unauthorized");// 没有权限访问时跳转的 url

        // 拦截请求
        LinkedHashMap<String, String> filterChainDefinitionMap = new LinkedHashMap<>();
        filterChainDefinitionMap.put("/user/index", "authc");// /index 必须登录
        filterChainDefinitionMap.put("/user/login", "anon");// /login 不需要任何拦截
        filterChainDefinitionMap.put("/user/loginUser", "anon");// /loginUser 接口不需要身份验证
        filterChainDefinitionMap.put("/user/admin", "roles[admin]");// /users/admin 只允许角色 admin 访问
        filterChainDefinitionMap.put("/user/edit", "perms[edit]");// 具有了edit权限的用户才可以访问
        filterChainDefinitionMap.put("/druid/*", "anon");// 放开druid所有拦截
        filterChainDefinitionMap.put("/**", "user");// 其他接口只要登录即可，权限拦截级别为user
        shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
        return shiroFilterFactoryBean;
    }

    /**
     * securityManager 将被 ShiroFilter 使用
     *
     * @param authRealm Spring 上下文的 authRealm
     * @return
     */
    @Bean("securityManager")
    public SecurityManager securityManager(@Qualifier("authRealm") AuthRealm authRealm) {
        DefaultWebSecurityManager manager = new DefaultWebSecurityManager();
        manager.setRealm(authRealm);
        return manager;
    }

    /**
     * @param credentialMatcher 从 Spring 上下文获取的 credentialMatcher
     * @return
     */
    @Bean("authRealm")
    public AuthRealm authRealm(@Qualifier("credentialMatcher") CredentialMatcher credentialMatcher) {
        AuthRealm authRealm = new AuthRealm();
        authRealm.setCacheManager(new MemoryConstrainedCacheManager());// 直接指定CacheManager
        authRealm.setCredentialsMatcher(credentialMatcher);// 自定义的密码比较器
        return authRealm;
    }

    /**
     * 自定义比较器
     *
     * @return
     */
    @Bean("credentialMatcher")
    public CredentialMatcher credentialMatcher() {
        return new CredentialMatcher();
    }

    /**
     * Shiro和Spring关联
     * Spring在对Shiro进行处理的时候使用的securityManager就是上面自定义的securityManager
     */
    @Bean
    public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(@Qualifier("securityManager") SecurityManager securityManager) {
        AuthorizationAttributeSourceAdvisor advisor = new AuthorizationAttributeSourceAdvisor();
        advisor.setSecurityManager(securityManager);// 传入实例化好的securityManager
        return advisor;
    }

    @Bean
    public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() {
        DefaultAdvisorAutoProxyCreator creator = new DefaultAdvisorAutoProxyCreator();
        creator.setProxyTargetClass(true);
        return creator;
    }
}
